﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Threading;
using System.Drawing;
using PluginInterfacesLib;
using System.Windows.Controls;

namespace GeoPlugin
{
    public sealed class PluginModel : INotifyPropertyChanged
    {
        private static readonly ReaderWriterLockSlim rwlock = new ReaderWriterLockSlim();
        private static readonly ReaderWriterLockSlim markerPositionsLock = new ReaderWriterLockSlim();
        
        private static List<Spat> markerPositions;
        private static Bitmap _image;
        public event PropertyChangedEventHandler PropertyChanged;
        private static Boolean _colorMarkerProcessorResultReceived;
        private static ColorMarkerProcessor colorMarkerProcessor;
        private static Thread colorMarkerProcessorThread;
        private static readonly PluginModel instance = new PluginModel();
        private static Bitmap markerImage;
        private static IPluginHost host;
        private static ObjectControl objectControl;
        private static bool runThread = true;
        private static ControlProcessor controlProcessor;
        private static Thread controlProcessorThread;


        public List<Spat> MarkerPositions
        {
            get
            {
                markerPositionsLock.EnterReadLock();
                try
                {
                    return markerPositions;
                }
                finally
                {
                    markerPositionsLock.ExitReadLock();
                }
            }
            set
            {
                markerPositionsLock.EnterWriteLock();
                try
                {
                    markerPositions = value; 
                    if (!controlProcessor.NewResultFromMarkerProcessor)
                    {
                        controlProcessor.NewResultFromMarkerProcessor = true;
                    }
                }
                finally
                {
                    markerPositionsLock.ExitWriteLock();
                }
            }
        }
        public bool RunThread
        {
            get { return PluginModel.runThread; }
            set { PluginModel.runThread = value; }
        }

        public ObjectControl ObjectControl
        {
            get { return PluginModel.objectControl; }
            set { PluginModel.objectControl = value; }
        }

        public IPluginHost Host
        {
            get { return PluginModel.host; }
            set { PluginModel.host = value; }
        }

        public Boolean ColorMarkerProcessorResultReceived
        {
            get { return _colorMarkerProcessorResultReceived; }
            set { _colorMarkerProcessorResultReceived = value; }
        }

        public ColorMarkerProcessor ColorMarkerProcessor
        {
            get { return colorMarkerProcessor; }
            set { colorMarkerProcessor = value; }
        }

        public Bitmap MarkerImage
        {
            get
            {
                return markerImage;

            }
            set
            {

                markerImage = value;
                if (value != null)
                {
                    OnPropertyChanged(this, new PropertyChangedEventArgs("MarkerImage"));
                }

            }
        }

        public Bitmap Image
        {

            get
            {
                rwlock.EnterWriteLock();
                try
                {
                    return new Bitmap(_image);
                }
                finally
                {
                    rwlock.ExitWriteLock();
                }
            }
            set
            {
                rwlock.EnterWriteLock();
                try
                {
                    _image = value;
                    if (value != null)
                    {
                        OnPropertyChanged(this, new PropertyChangedEventArgs("Image"));
                        if (!colorMarkerProcessor.NewResultFromWebcam)
                        {
                            colorMarkerProcessor.NewResultFromWebcam = true;
                        }
                    }
                }
                finally
                {
                    rwlock.ExitWriteLock();
                }
            }
        }

        private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(sender, e);
            }
        }

        public static PluginModel Instance
        {
            get
            {
                return PluginModel.instance;
            }
        }

        public PluginModel()
        {
            List<Spat> spats = new List<Spat>();
            Spat spat = new Spat(Color.FromArgb(217, 151, 79), 30.0);
            Spat spat1 = new Spat(Color.FromArgb(83, 183, 123), 30.0);
            spats.Add(spat);
            spats.Add(spat1);
            colorMarkerProcessor = new ColorMarkerProcessor(spats);
            colorMarkerProcessorThread = new Thread(new ThreadStart(colorMarkerProcessor.Run));
            colorMarkerProcessorThread.Name = "ColorMarkerProcessorThread from GeoPlugin.";
            colorMarkerProcessor.NewResult += this.MarkerProcessorResultReceived;
            controlProcessor = new ControlProcessor();
            controlProcessorThread = new Thread(new ThreadStart(controlProcessor.ThreadRun));
            MarkerImage = ImageProcessing.NewEmptyImage(320, 240, Color.Black);
            MarkerImage.MakeTransparent(Color.Black);
            Image = ImageProcessing.NewEmptyImage(320, 240, Color.Black);
            markerPositions = new List<Spat>(spats.Count);
        }

        public void MarkerProcessorResultReceived(object sender, EventArgs args)
        {
            ColorMarkerProcessorResultReceived = true;
        }


        private bool firstTime = true;
        public void ThreadRun()
        {
            Thread.Sleep(1000);
            while (runThread)
            {
                PluginModel.Instance.Image = (Bitmap)host.GetWebcamImage();
                if (firstTime)
                {
                    controlProcessor.ImageHeight = Image.Height;
                    controlProcessor.ImageWidth = Image.Width;
                    firstTime = false;
                }
                if (!colorMarkerProcessorThread.IsAlive && colorMarkerProcessorThread.ThreadState != ThreadState.Stopped)
                {
                    colorMarkerProcessor.RunThread = true;
                    colorMarkerProcessorThread.Start();
                }
                if (!controlProcessorThread.IsAlive && colorMarkerProcessorThread.ThreadState != ThreadState.Stopped)
                {
                    controlProcessor.ObjectControl = ObjectControl;
                    controlProcessor.RunThread = true;
                    controlProcessorThread.Start();
                }

                if (_colorMarkerProcessorResultReceived)
                {
                    PluginModel.Instance.MarkerImage = colorMarkerProcessor.MarkerImage;
                    PluginModel.Instance.MarkerPositions = new List<Spat>(colorMarkerProcessor.Spats);
                    _colorMarkerProcessorResultReceived = false;
                }
                Thread.Sleep(30);
            }
            colorMarkerProcessor.RunThread = false;
            controlProcessor.RunThread = false;
        }
    }
}
